#include "5.h"

unsigned ialloc() //申请一个未使用的i节点号
{
    if (su_b.s_ninode == 0) //无直接管理的空闲i节点
    {
        if (su_b.s_inode[0] == 0) //空闲栈底为空，无空闲i节点号
        {
            printf("无空闲i节点号，申请i节点号失败!\n");
            return 0;
        }
        else
        {
            unsigned num = su_b.s_inode[0];
            fseek(fp, I(num), SEEK_SET); //找到第num个i节点的起始地址
            //将栈底i节点保存的空闲i节点读入空闲i节点管理栈
            if (fread(su_b.s_inode, sizeof(unsigned), I_FREE_NUM, fp) != I_FREE_NUM)
            {
                printf("读取i节点到i节点管理栈失败!  申请第%d个i节点失败!\n", num);
                return 0;
            }
            su_b.s_ninode = I_FREE_NUM - 1;
            return num;
        }
    }
    else
    {
        su_b.s_ninode--;
        return su_b.s_inode[su_b.s_ninode + 1];
    }
}

bool ifree(unsigned num) //归还一个i节点号
{
    if (num <= 0)
    {
        printf("将i节点管理栈写入到归还的i节点失败! 归还第%d个i节点失败\n", num);
        return false;
    }
    su_b.s_ninode++;
    if (su_b.s_ninode < I_FREE_NUM) //空闲i节点号栈未满
    {
        su_b.s_inode[su_b.s_ninode] = num;
    }
    else //空闲i节点号栈满
    {
        fseek(fp, I(num), SEEK_SET); //找到第num个i节点的起始地址
        //将直接管理的i节点号写入归还的i节点中
        if (fwrite(su_b.s_inode, sizeof(unsigned), I_FREE_NUM, fp) != I_FREE_NUM)
        {
            printf("将i节点管理栈写入到归还的i节点失败! 归还第%d个i节点失败\n", num);
            su_b.s_ninode--;
            return false;
        }
        su_b.s_ninode = 0; //直接管理的i节点数目置0
        su_b.s_inode[0] = num;
    }
    return true;
}

bool iread(inode *i, unsigned num) //读取第num个i节点到内存
{
    if (num <= 0) //读取i节点到i节点缓冲区
    {
        printf("读取第%d个i节点到内存失败!\n", num);
        return false;
    }
    fseek(fp, I(num), SEEK_SET);             //找到第num个i节点的起始地址
    if (fread(i, sizeof(inode), 1, fp) != 1) //读取i节点到i节点缓冲区
    {
        printf("读取第%d个i节点到内存失败!\n", num);
        return false;
    }
    return true;
}

bool iwrite(inode *i, unsigned num) //写第num个i节点到磁盘
{
    if (num <= 0)
    {
        printf("读写第%d个i节点到磁盘失败!\n", num);
        return false;
    }
    fseek(fp, I(num), SEEK_SET);              //找到第num个i节点的起始地址
    if (fwrite(i, sizeof(inode), 1, fp) != 1) //将i节点缓冲区数据写入到磁盘
    {
        printf("读写第%d个i节点到磁盘失败!\n", num);
        return false;
    }
    return true;
}

bool set_imode(inode *i, const char *mode) //设置各类用户权限
{
    if (strlen(mode) != 3)
    {
        printf("设置i节点各类用户权限失败[权限格式错误]！\n");
        return 0;
    }
    else
    {
        unsigned temp = 0;
        for (int i = 0; i < 3; i++)
        {
            temp <<= 3;
            temp += mode[i] - '0';
        }
        i->i_mode = temp;
        // printf("%u\n", temp);
        return true;
    }
}

unsigned balloc() //申请一个空数据块
{
    if (su_b.s_nfree == 0) //无直接管理的空闲数据块
    {
        if (su_b.s_free[0] == 0) //空闲栈底为空，无空闲数据块
        {
            printf("无空闲数据块，申请数据块失败!\n");
            return 0;
        }
        else
        {
            unsigned num = su_b.s_free[0];
            fseek(fp, D(num), SEEK_SET); //找到第num个数据块的起始地址
            //将栈底数据块保存的空闲数据块信息读入空闲数据块管理栈
            if (fread(su_b.s_free, sizeof(unsigned), B_FREE_NUM, fp) != B_FREE_NUM)
            {
                printf("将栈底数据块保存的空闲数据块信息读入空闲数据块管理栈失败!\n");
                return 0;
            }
            su_b.s_nfree = B_FREE_NUM - 1;
            return num;
        }
    }
    else
    {
        return su_b.s_free[su_b.s_nfree--];
    }
}

bool bfree(unsigned num) //归还一个数据块
{
    if (num <= 0)
    {
        printf("归还数据块失败!\n");
        return false;
    }
    su_b.s_nfree++;
    if (su_b.s_nfree < B_FREE_NUM) //空闲块号栈未满
    {
        su_b.s_free[su_b.s_nfree] = num;
    }
    else //空闲块号栈满
    {
        fseek(fp, D(num), SEEK_SET); //找到第num个数据块的起始地址
        //将直接管理的数据块号写入归还的数据块中
        if (fwrite(su_b.s_free, sizeof(unsigned), B_FREE_NUM, fp) != B_FREE_NUM)
        {
            printf("将直接管理的数据块号写入归还的数据块失败!\n");
            return false;
        }
        su_b.s_nfree = 0; //直接管理的数据块数目置0
        su_b.s_free[0] = num;
    }
    return true;
}

//读取第num个数据块到内存，mode:文件类型
bool bread(void *buf, unsigned num, unsigned mode)
{
    if (num <= 0)
    {
        printf("读取第%d个文件数据块失败!\n", num);
        return false;
    }
    fseek(fp, D(num), SEEK_SET);
    switch (mode)
    {
    case NORMAL: //数据块内容为文件数据
        if (fread((char *)buf, sizeof(char), BLOCK_SIZE, fp) != BLOCK_SIZE)
        {
            printf("读取第%d个文件数据块失败!\n", num);
            return false;
        }
        break;
    case DIR: //数据块内容为目录数据
        if (fread((dirs *)buf, sizeof(dirs), 1, fp) != 1)
        {
            printf("读取第%d个目录数据块失败!\n", num);
            return false;
        }
        break;
    case PWD: //数据块内容为用户账号密码数据
        if (fread((pwd *)buf, sizeof(pwd), 1, fp) != 1)
        {
            printf("读取第%d个用户数据块失败!\n", num);
            return false;
        }
        break;
    case SUPBLK: //数据块内容为超级块
        fseek(fp, BLOCK_SIZE, SEEK_SET);
        if (fread((super_block *)buf, sizeof(super_block), 1, fp) != 1)
        {
            printf("读取超级块失败!\n");
            return false;
        }
        break;
    default:
        break;
    }
    return true;
}

//写入数据到第num个数据块，mode:文件类型
bool bwrite(void *buf, unsigned num, unsigned mode)
{
    if (num <= 0)
    {
        printf("写入数据到第%d个数据块失败!\n", num);
        return false;
    }
    fseek(fp, D(num), SEEK_SET);
    switch (mode)
    {
    case NORMAL: //数据块内容为文件数据
        if (fwrite((char *)buf, sizeof(char), BLOCK_SIZE, fp) != BLOCK_SIZE)
        {
            printf("写入数据到第%d个数据块失败!\n", num);
            return false;
        }
        break;
    case DIR: //数据块内容为目录数据
        if (fwrite((dirs *)buf, sizeof(dirs), 1, fp) != 1)
        {
            printf("写入数据到第%d个数据块失败!\n", num);
            return false;
        }
        break;
    case PWD: //数据块内容为用户账号密码数据
        if (fwrite((pwd *)buf, sizeof(pwd), 1, fp) != 1)
        {
            printf("写入数据到第%d个数据块失败!\n", num);
            return false;
        }
        break;
    case SUPBLK: //数据块内容为超级块
        fseek(fp, BLOCK_SIZE, SEEK_SET);
        if (fwrite((super_block *)buf, sizeof(super_block), 1, fp) != 1)
        {
            printf("写回超级块失败!\n");
            return false;
        }
        break;
    default:
        break;
    }
    return true;
}

bool format() //格式化文件系统
{
    time(&(ino.i_time));
    ino.i_uid = 0;
    ino.i_type = DIR;
    if (set_imode(&ino, "744") == false)
    {
        printf("设置1号i节点权限错误!\n");
        return false;
    }
    ino.i_ilink = 1;
    ino.i_size = 3;
    ino.i_addr[0] = 1;
    for (int i = 1; i < I_ADDR_NUM; i++)
        ino.i_addr[i] = 0;
    if (iwrite(&ino, 1) == false) //将1号i节点写入磁盘
        return false;

    dir.entry[0].dir_id = 1;
    strcpy(dir.entry[0].dir_name, ".");
    dir.entry[1].dir_id = 1;
    strcpy(dir.entry[1].dir_name, "..");
    dir.entry[2].dir_id = 2;
    strcpy(dir.entry[2].dir_name, "etc");
    for (int i = 3; i < DIR_NUM; i++)
        dir.entry[i].dir_id = 0;
    if (bwrite(&dir, 1, DIR) == false) //将根节点目录信息写入1号数据块
        return false;

    time(&(ino.i_time));
    ino.i_uid = 0;
    ino.i_type = DIR;
    if (set_imode(&ino, "744") == false)
    {
        printf("设置2号i节点权限错误!\n");
        return false;
    }
    ino.i_ilink = 1;
    ino.i_size = 3;
    ino.i_addr[0] = 2;
    for (int i = 1; i < I_ADDR_NUM; i++)
        ino.i_addr[i] = 0;
    if (iwrite(&ino, 2) == false) //将2号i节点写入磁盘
        return false;

    dir.entry[0].dir_id = 2;
    strcpy(dir.entry[0].dir_name, ".");
    dir.entry[1].dir_id = 1;
    strcpy(dir.entry[1].dir_name, "..");
    dir.entry[2].dir_id = 3;
    strcpy(dir.entry[2].dir_name, "password");
    for (int i = 3; i < DIR_NUM; i++)
        dir.entry[i].dir_id = 0;
    if (bwrite(&dir, 2, DIR) == false) //将/etc目录信息写入2号数据块
        return false;

    time(&(ino.i_time));
    ino.i_uid = 0;
    ino.i_type = NORMAL;
    if (set_imode(&ino, "700") == false)
    {
        printf("设置3号i节点权限错误!\n");
        return false;
    }
    ino.i_ilink = 1;
    ino.i_size = BLOCK_SIZE;
    ino.i_addr[0] = 3;
    for (int i = 1; i < I_ADDR_NUM; i++)
        ino.i_addr[i] = 0;
    if (iwrite(&ino, 3) == false) //将3号i节点写入磁盘
        return false;

    pd.current_usr = 0;
    pd.all_usr = 1;
    pd.entry[0].p_uid = 0;
    strcpy(pd.entry[0].user_name, "root");
    strcpy(pd.entry[0].password, "czy996421");
    for (int i = 1; i < USER_NUM; i++)
        pd.entry[i].p_uid = -1;
    if (bwrite(&pd, 3, PWD) == false) //将用户账号密码信息写入3号数据块
        return false;

    //初始化超级块
    su_b.s_isize = I_BLOCK_NUM;
    su_b.s_fsize = FILE_SYS_SIZE;
    su_b.s_nfree = 0;
    su_b.s_free[0] = 0;
    su_b.s_ninode = 0;
    su_b.s_inode[0] = 0;
    time(&(su_b.s_time));
    for (int i = DATA_NUM; i > 3; i--)
        bfree(i);
    for (int i = I_NUM; i > 3; i--)
        ifree(i);
    if (bwrite(&su_b, 1, SUPBLK) == false) //写回超级块
        return false;

    return true;
}

bool loadSystem() //载入文件系统
{
    if (access("system_disk", F_OK) == 0) //文件系统存在，打开文件
    {
        if ((fp = fopen("system_disk", "rb+")) == NULL)
        {
            printf("打开文件系统文件失败!\n");
            return false;
        }
        else
        {
            if (bread(&su_b, 1, SUPBLK) == false) //读入超级块
                return false;
            if (bread(&pd, 3, PWD) == false) //读入用户信息块
                return false;
            printf("载入文件系统成功...\n");
        }
    }
    else //文件系统不存在，创建文件系统并格式化
    {
        if ((fp = fopen("system_disk", "wb+")) == NULL) //创建文件系统
        {
            printf("创建文件系统文件失败!\n");
            return false;
        }
        else
            printf("创建文件系统文件成功...\n");
        //设置文件系统大小
        char eof = EOF;
        fseek(fp, FILE_SYS_SIZE * BLOCK_SIZE - 1, SEEK_SET);
        fwrite(&eof, 1, 1, fp);
        if (format() == false) //格式化文件系统
        {
            printf("格式化文件系统文件失败!\n");
            return false;
        }
        else
            printf("格式化文件系统文件成功...\n");
    }
    if (iread(&ino, 1) == false) //读入根目录i节点
        return false;
    current_i = 1; //当前i节点号为1，即位于根目录
    return true;
}

bool printCommandTip() //打印命令提示头
{
    char cur_path[128];
    memset(cur_path, '\0', 128);
    printWorkingDir(cur_path, current_i);
    printf("\033[1;34m%s@system_disk\033[0m:%s$ ",
           pd.entry[pd.current_usr].user_name, cur_path);
    return true;
}

bool checkRWX(unsigned cur_i, unsigned rwx) //权限检测
{
    inode tmp_inode;
    if (!iread(&tmp_inode, cur_i))
        return false;
    if (tmp_inode.i_uid == pd.current_usr || pd.current_usr == 0) //当前用户是当前文件夹拥有者/root
    {
        if (((tmp_inode.i_mode >> 6) & rwx) == rwx) //权限对比
            return true;
        else
            return false;
    }
    else
    {
        if ((tmp_inode.i_mode & rwx) == rwx) //权限对比
            return true;
        else
            return false;
    }
}

//向目标i节点目录加入文件
bool addFileToDir(char *file_name, unsigned src_i, unsigned des_i)
{
    inode temp_inode;
    dirs temp_dirs;
    if (!iread(&temp_inode, des_i)) //将目标i节点读入
        return false;
    if (temp_inode.i_type != DIR) //判断该i节点文件类型
        return false;
    int addr_num = temp_inode.i_size / DIR_NUM;
    int dir_num = temp_inode.i_size % DIR_NUM;
    if (temp_inode.i_size && dir_num == 0 && addr_num < I_ADDR_NUM) //判断是否需要增加目录数据块
    {
        if ((temp_inode.i_addr[addr_num] = balloc()) == 0) //申请新的目录数据块
            return false;
    }
    else if (temp_inode.i_size == I_ADDR_NUM * DIR_NUM)
    {
        printf("该文件夹下目录项已满，无法加入新文件i节点\n");
        return false;
    }
    if (!bread(&temp_dirs, temp_inode.i_addr[addr_num], DIR)) //将目录数据块读出
        return false;
    temp_dirs.entry[dir_num].dir_id = src_i;
    strcpy(temp_dirs.entry[dir_num].dir_name, file_name);
    temp_inode.i_size++;
    if (!bwrite(&temp_dirs, temp_inode.i_addr[addr_num], DIR)) //将更新后的目录数据块写回
        return false;
    if (!iwrite(&temp_inode, des_i)) //将更新后的i节点写回
        return false;
    return true;
}

bool checkName(char *file_name, unsigned cur_i) //判断当前目录下是否有同名文件
{
    inode tmp_inode;
    dirs tmp_d;
    if (!iread(&tmp_inode, cur_i))
        return false;
    int j = 0;
    for (int i = 0; i < tmp_inode.i_size; i++, j++) //逐个对比目录项
    {
        if (i % DIR_NUM == 0) //当到达一个目录数据块最大目录项个数时，读入下一个目录数据块
        {
            if (!bread(&tmp_d, tmp_inode.i_addr[i / DIR_NUM], DIR)) //将目录项数据块读入
                return false;
            j = 0;
        }
        if (strcmp(tmp_d.entry[j].dir_name, file_name) == 0) //出现重名文件
            return false;
    }
    return true;
}

bool refrushTime(char *file_name, unsigned cur_i) //更新文件或目录时间戳
{
    inode tmp_inode, son_i;
    dirs tmp_d;
    if (!iread(&tmp_inode, cur_i))
        return false;
    int j = 0;
    for (int i = 0; i < tmp_inode.i_size; i++, j++) //逐个对比目录项
    {
        if (i % DIR_NUM == 0) //当到达一个目录数据块最大目录项个数时，读入下一个目录数据块
        {
            if (!bread(&tmp_d, tmp_inode.i_addr[i / DIR_NUM], DIR)) //将目录项数据块读入
                return false;
            j = 0;
        }
        if (strcmp(tmp_d.entry[j].dir_name, file_name) == 0) //找到需要更新时间的文件
        {
            if (!iread(&son_i, tmp_d.entry[j].dir_id)) //读入需更新时间文件的i节点
                return true;
            time(&(son_i.i_time));
            if (!iwrite(&son_i, tmp_d.entry[j].dir_id)) //写回更新文件
                return false;
            return true;
        }
    }
    return false;
}

bool createFile(char *file_name, unsigned mode) //创建新文件
{
    char pwd_buf[1024];
    printWorkingDir(pwd_buf, current_i);
    if (filePath2inode(pwd_buf, current_i, 3, DIR) == -2) //判断从根目录到当前目录是否有可写可执行权限
        // if (!checkRWX(current_i, 3))
    {
        printf("权限不足，无法创建文件!\n");
        return false;
    }
    unsigned temp_inode = ialloc(); //申请一个空闲i节点号
    if (temp_inode == 0)
    {
        printf("申请i节点失败!\n");
        return false;
    }
    switch (mode)
    {
    case NORMAL:                       //普通文件
        t_ino.i_uid = pd.current_usr;  //设置文件所有者标识
        t_ino.i_type = NORMAL;         //设置文件类型
        if (!set_imode(&t_ino, "644")) //设置所创建的文件权限: rw-r--r--
        {
            printf("设置%d号i节点权限错误!\n", temp_inode);
            ifree(temp_inode); //归还i节点
            return false;
        }
        t_ino.i_ilink = 1;                   //设置文件联接计数
        for (int i = 0; i < I_ADDR_NUM; i++) //初始化地址索引表
            t_ino.i_addr[i] = 0;
        t_ino.i_size = 0; //设置文件大小
        time(&(t_ino.i_time));
        if (!iwrite(&t_ino, temp_inode)) //将i节点写入到磁盘
        {
            ifree(temp_inode); //归还i节点
            return false;
        }
        if (!addFileToDir(file_name, temp_inode, current_i)) //将新建文件i节点和文件名加入到目录
        {
            printf("将新建文件加入到本目录失败\n");
            ifree(temp_inode); //归还i节点
            return false;
        }
        break;
    case DIR: //目录文件
    {
        dirs temp_dirs;
        t_ino.i_uid = pd.current_usr;  //设置文件所有者标识
        t_ino.i_type = DIR;            //设置文件类型
        if (!set_imode(&t_ino, "755")) //设置所创建的文件权限: rwxr-xr-x
        {
            printf("设置%d号i节点权限错误!\n", temp_inode);
            ifree(temp_inode); //归还i节点
            return false;
        }
        t_ino.i_ilink = 1;                     //设置文件联接计数
        if ((t_ino.i_addr[0] = balloc()) == 0) //申请一个数据块
        {
            printf("申请数据块失败!\n");
            ifree(temp_inode); //归还i节点
            return false;
        }
        for (int i = 1; i < I_ADDR_NUM; i++) //初始化地址索引表
            t_ino.i_addr[i] = 0;
        t_ino.i_size = 2; //设置文件大小, 表示文件夹中文件数目
        temp_dirs.entry[0].dir_id = temp_inode;
        strcpy(temp_dirs.entry[0].dir_name, ".");
        temp_dirs.entry[1].dir_id = current_i;
        strcpy(temp_dirs.entry[1].dir_name, "..");
        for (int i = 2; i < DIR_NUM; i++)
            temp_dirs.entry[i].dir_id = 0;
        if (bwrite(&temp_dirs, t_ino.i_addr[0], DIR) == false) //将初始化目录内容写入
            return false;
        time(&(t_ino.i_time));
        if (!iwrite(&t_ino, temp_inode)) //将i节点写入到磁盘
        {
            ifree(temp_inode);      //归还i节点
            bfree(t_ino.i_addr[0]); //归还数据块
            return false;
        }
        if (!addFileToDir(file_name, temp_inode, current_i)) //将新建目录i节点和文件名加入到目录
        {
            printf("将新建目录加入到本目录失败\n");
            ifree(temp_inode);      //归还i节点
            bfree(t_ino.i_addr[0]); //归还数据块
            return false;
        }
    }
    break;
    default:
        printf("其他文件暂未支持\n");
        ifree(temp_inode); //归还i节点
        return false;
    }
    return true;
}

bool catFile(char *file_path) //查看文件内容
{
    if (!_open(file_path))
    {
        printf("打开文件失败\n");
        return false;
    }
    if (open_ino.i_size == 0)
        return true;
    char temp_buf[BLOCK_SIZE + 5];
    int loc = 0;
    memset(temp_buf, '\0', BLOCK_SIZE + 5);
    while (true)
    {
        if (!_read(loc, temp_buf))
            break;
        if (strlen(temp_buf) == 0)
            break;
        loc += BLOCK_SIZE;
        // puts(temp_buf);
        for (int i = 0; i < BLOCK_SIZE; i++)
        {
            if (temp_buf[i] == EOF) //到达文件尾
                break;
            putchar(temp_buf[i]);
        }
        putchar('\n');
        memset(temp_buf, '\0', BLOCK_SIZE + 5);
    }
    if (!_close(open_i))
    {
        printf("关闭文件失败\n");
        return false;
    }

    return true;
}

bool vi_file(char *file_path) //编辑文件
{
    if (!catFile(file_path))
        return false;
    char temp_buf[5 * BLOCK_SIZE];
    // gets(temp_buf);
    for (int i = 0; i < 5 * BLOCK_SIZE; i++)
    {
        temp_buf[i] = getchar();
        if (temp_buf[i] == EOF)
        {
            temp_buf[i] = '\0';
            break;
        }
    }
    if (!_open(file_path))
    {
        return false;
    }
    if (!_write(temp_buf, strlen(temp_buf)))
        return false;
    if (!_close(open_i))
    {
        return false;
    }
    return true;
}

void getAuthorityBuf(char *buf, unsigned short mode) //将文件权限转换为字符串
{
    char rwx[4] = "rwx";
    unsigned short mark = 0x100;
    for (int i = 0; i < 9; i++)
    {
        if (mode & mark)
            buf[i] = rwx[i % 3];
        else
            buf[i] = '-';
        mark >>= 1;
    }
    buf[9] = '\0';
}

bool showDir(char *mode) //显示当前文件夹中内容
{
    if (!checkRWX(current_i, 5))
    {
        printf("ls: 权限不够\n");
        return false;
    }
    bool l, a, p; //列表详细信息显示、显示隐藏文件、给文件夹后加/
    l = a = p = false;
    int mode_length = strlen(mode);
    for (int i = 0; i < mode_length; i++)
    {
        switch (mode[i])
        {
        case 'l':
            l = true;
            break;
        case 'a':
            a = true;
            break;
        case 'p':
            p = true;
            break;
        default:
            break;
        }
    }
    char cont[1024];                //保存输出信息
    inode temp_i, temp_son_i;       //当前目录i节点信息以及其儿子i节点信息
    dirs temp_dirs;                 //当前目录信息
    if (!iread(&temp_i, current_i)) //读入当前文件夹i节点信息
        return false;
    int j = 0;
    for (int i = 0; i < temp_i.i_size; i++, j++)
    {
        if (i % DIR_NUM == 0) //当到达一个目录数据块最大目录项个数时，读入下一个目录数据块
        {
            if (!bread(&temp_dirs, temp_i.i_addr[i / DIR_NUM], DIR)) //将目录项数据块读入
                return false;
            j = 0;
        }
        if (!iread(&temp_son_i, temp_dirs.entry[j].dir_id)) //读入当前文件夹子文件i节点信息
            return false;
        if (!a && temp_dirs.entry[j].dir_name[0] == '.') //隐藏文件不显示
            continue;
        if (l) //列表详细信息显示
        {
            if (temp_son_i.i_type == DIR) //判断文件是否为目录
                printf("d");
            else
                printf("-");
            getAuthorityBuf(cont, temp_son_i.i_mode); //将文件权限转换为字符串
            printf("%s %u %u ", cont, temp_son_i.i_uid, temp_dirs.entry[j].dir_id);
            strftime(cont, sizeof(cont), "%Y-%m-%d %H:%M:%S", localtime(&(temp_son_i.i_time))); //时间转换为本地时间
            printf("%s ", cont);
        }

        if (p) //文件夹后加/
        {
            if (temp_son_i.i_type == DIR) //判断文件是否为目录，并将其输出颜色置为绿色
                printf("\033[1;32m%s/\033[0m ", temp_dirs.entry[j].dir_name);
            else
                printf("%s ", temp_dirs.entry[j].dir_name);
        }
        else //文件夹后不加/
            printf("%s ", temp_dirs.entry[j].dir_name);
        if (i != temp_i.i_size - 1 && l)
            printf("\n");
    }
    printf("\n");
    return true;
}

int filePath2inode(char *path, unsigned cur_i, unsigned mode, unsigned type) //根据文件路径找到该文件i节点号
{
    char tmp_name[32], next_path[128];
    if (strlen(path) == 0)
    {
        return cur_i;
    }
    if (path[0] == '/')
    {
        strcpy(next_path, path + 1);
        return filePath2inode(next_path, 1, mode, type);
    }
    inode tmp_i, tt_i;
    dirs tmp_d;
    if (!iread(&tmp_i, cur_i))
        return false;
    if (strstr(path, "/") == NULL) //路径结束，以不带/的文件结束
    {
        //从目录项中寻找该文件
        int j = 0;
        for (int i = 0; i < tmp_i.i_size; i++, j++)
        {
            if (i % DIR_NUM == 0) //当到达一个目录数据块最大目录项个数时，读入下一个目录数据块
            {
                if (!bread(&tmp_d, tmp_i.i_addr[i / DIR_NUM], DIR)) //将目录项数据块读入
                    return false;
                j = 0;
            }
            if (strcmp(tmp_d.entry[j].dir_name, path) == 0)
            {
                if (!iread(&tt_i, tmp_d.entry[j].dir_id))
                    return false;
                if (type == DIR && tt_i.i_type != DIR) //判断所取文件i节点类型是否正确
                {
                    // printf("不是目录: %s\n", path);
                    return -1;
                }
                if (type == DIR && !checkRWX(tmp_d.entry[j].dir_id, mode)) //检测是否有相应权限
                {
                    // printf("权限不够: %u\n", mode);
                    return -2;
                }
                return tmp_d.entry[j].dir_id;
            }
        }
    }
    else
    {
        sscanf(path, "%[^/]", tmp_name);
        int j = 0;
        for (int i = 0; i < tmp_i.i_size; i++, j++) //从目录项中寻找该文件夹
        {
            if (i % DIR_NUM == 0) //当到达一个目录数据块最大目录项个数时，读入下一个目录数据块
            {
                if (!bread(&tmp_d, tmp_i.i_addr[i / DIR_NUM], DIR)) //将目录项数据块读入
                    return false;
                j = 0;
            }
            if (strcmp(tmp_d.entry[j].dir_name, tmp_name) == 0)
            {
                if (!iread(&tt_i, tmp_d.entry[j].dir_id))
                    return false;
                if (tt_i.i_type != DIR) //检测待进入文件是否为目录
                {
                    // printf("不是目录: %s\n", path);
                    return -1;
                }
                if (!checkRWX(tmp_d.entry[j].dir_id, mode)) //检测是否有执行权限
                {
                    // printf("权限不够: %u\n", mode);
                    return -2;
                }
                return filePath2inode(strstr(path, "/") + 1, tmp_d.entry[j].dir_id, mode, type);
            }
        }
    }
    return false;
}

bool changeDir(char *path, unsigned cur_i) //改变当前工作目录
{
    char temp_path[1024];
    int temp_i;
    strcpy(temp_path, path);
    if ((temp_i = filePath2inode(temp_path, cur_i, 1, DIR)) == 0) //权限为 --x
    {
        printf("cd: 目录不存在: %s\n", path);
        return false;
    }
    else if (temp_i == -2)
    {
        printf("cd: 权限不够: %s\n", path);
        return false;
    }
    else if (temp_i == -1)
    {
        printf("cd: 不是目录: %s\n", path);
        return false;
    }
    else
        current_i = temp_i;
    return true;
}

bool inode2name(unsigned far_i, unsigned cur_i, char *name) //根据父文件和文件i节点获取文件名
{
    if (cur_i == 1) //为根目录
    {
        strcpy(name, "/");
        return true;
    }
    inode tmp_i;
    dirs tmp_d;
    if (!iread(&tmp_i, far_i)) //将i节点读入
        return false;
    if (!bread(&tmp_d, tmp_i.i_addr[0], DIR)) //将目录项数据块读入
        return false;
    int j = 0;
    for (int i = 0; i < tmp_i.i_size; i++, j++) //从目录项中寻找该文件夹
    {
        if (i % DIR_NUM == 0) //当到达一个目录数据块最大目录项个数时，读入下一个目录数据块
        {
            if (!bread(&tmp_d, tmp_i.i_addr[i / DIR_NUM], DIR)) //将目录项数据块读入
                return false;
            j = 0;
        }
        if (tmp_d.entry[j].dir_id == cur_i)
        {
            strcpy(name, tmp_d.entry[j].dir_name);
            return true;
        }
    }
    return false;
}

bool printWorkingDir(char *workpath, unsigned cur_i) //获取当前工作目录路径
{
    if (cur_i == 1) //到达根目录
    {
        char temp_path[128];
        strcpy(temp_path, workpath);
        sprintf(workpath, "/%s", temp_path);
        return true;
    }
    inode tmp_i;
    dirs tmp_d;
    if (!iread(&tmp_i, cur_i)) //将i节点读入
        return false;
    if (!bread(&tmp_d, tmp_i.i_addr[0], DIR)) //将目录项数据块读入
        return false;
    char temp_path[128];
    if (!inode2name(tmp_d.entry[1].dir_id, cur_i, temp_path))
    {
        printf("通过i节点获取文件名失败\n");
        return false;
    }
    strcat(temp_path, "/");
    strcat(temp_path, workpath);
    strcpy(workpath, temp_path);
    return printWorkingDir(workpath, tmp_d.entry[1].dir_id);
}

bool relative2absolute(char *path, unsigned cur_i) //相对路径转绝对路径
{
    char temp[1024];
    strcpy(temp, path);
    memset(path, '\0', sizeof(path));
    printWorkingDir(path, cur_i);
    strcat(path, temp);
    // printf("%s\n", path);
    return true;
}

unsigned getFartherInode(char *filepath) //获取当前i节点的父亲i节点
{
    if (strcmp(filepath, "/") == 0)
        return 1;
    char temp_path[1024];
    int i, j;
    strcpy(temp_path, filepath);
    i = strlen(temp_path) - 2;
    while (temp_path[i] != '/')
        i--;

    if (i == 0)
        return 1;
    else
    {
        temp_path[i] = '\0';
        return filePath2inode(temp_path, 1, 0, DIR);
    }
}

bool removeDirFile(unsigned rm_i) //删除文件
{
    inode rm_inode, tmp_i;
    dirs tmp_d;
    int j = 2;
    if (!iread(&rm_inode, rm_i)) //读入待删除文件i节点
        return false;
    if (rm_inode.i_ilink == 1) //文件联接数为1, 删除文件i节点和数据块
    {
        if (rm_inode.i_type == DIR) //待删除文件为目录
        {
            // printf("%d\n", rm_inode.i_ilink);
            if (!bread(&tmp_d, rm_inode.i_addr[0], DIR)) //将目录项数据块读入
                return false;
            for (int i = 2; i < rm_inode.i_size; i++, j++) //逐个删除目录项
            {
                if (i % DIR_NUM == 0) //当到达一个目录数据块最大目录项个数时，读入下一个目录数据块
                {
                    if (!bread(&tmp_d, rm_inode.i_addr[i / DIR_NUM], DIR)) //将目录项数据块读入
                        return false;
                    j = 0;
                }
                // if (!iread(&tmp_i, tmp_d.entry[j].dir_id)) //读出每个目录项的i节点
                //     return false;
                if (!removeDirFile(tmp_d.entry[j].dir_id))
                    return false;
            }
            for (int i = 0; i < I_ADDR_NUM; i++) //释放目录项数据块
            {
                if (rm_inode.i_addr[i] == 0)
                    break;
                if (!bfree(rm_inode.i_addr[i]))
                    return false;
            }
            if (!ifree(rm_i)) //归还i节点
                return false;
        }
        else //待删除文件为普通文件
        {
            int i;
            for (i = 0; i < 9 && rm_inode.i_addr[i] != 0; i++) //归还直接索引数据块
            {
                if (!bfree(rm_inode.i_addr[i]))
                    return false;
            }
            if (i == 9) //存在一级间接索引
            {
                unsigned temp_addi[BLOCK_SIZE / sizeof(unsigned)];
                if (!bread(temp_addi, rm_inode.i_addr[9], NORMAL)) //读出一级间接索引数据块号
                    return false;
                for (i = 0; (i < BLOCK_SIZE / sizeof(unsigned)) && temp_addi[i] != 0; i++) //归还一级间接索引数据块
                {
                    if (!bfree(temp_addi[i]))
                        return false;
                }
            }
            if (!ifree(rm_i)) //归还i节点
                return false;
        }
    }
    else //文件联接数大于1, 文件联接数-1
    {
        rm_inode.i_ilink--;
    }
    return true;
}

bool removeFileFromFar(unsigned far_i, unsigned rm_i) //从far_i目录中删除rm_i节点
{
    inode far_inode;
    dirs far_d, far_d_last;
    if (!iread(&far_inode, far_i))
        return false;
    int i, j = 0;
    for (i = 0; i < far_inode.i_size; i++, j++)
    {
        if (i % DIR_NUM == 0) //当到达一个目录数据块最大目录项个数时，读入下一个目录数据块
        {
            if (!bread(&far_d, far_inode.i_addr[i / DIR_NUM], DIR)) //将目录项数据块读入
                return false;
            j = 0;
        }
        if (rm_i == far_d.entry[j].dir_id) //在父目录中找到要删除的目录项
        {
            int m = (far_inode.i_size - 1) / DIR_NUM;
            int n = (far_inode.i_size - 1) % DIR_NUM;
            if (!bread(&far_d_last, far_inode.i_addr[m], DIR)) //读取最后一个目录数据块
                return false;
            //将目录项中的最后一项覆盖掉要删除的目录项
            strcpy(far_d.entry[j].dir_name, far_d_last.entry[n].dir_name);
            far_d.entry[j].dir_id = far_d_last.entry[n].dir_id;
            far_inode.i_size--;

            if (!bwrite(&far_d, far_inode.i_addr[i / DIR_NUM], DIR)) //写回所删除目录项所在的数据块
                return false;
            if (i / DIR_NUM != m) //所要删除的目录项与最后一项目录项不在同一个数据块上
            {
                if (m != 0 && n == 0) //最后一个目录项独自占用一个数据块
                {
                    if (!bfree(far_inode.i_addr[m])) //释放最后一个目录数据块
                        return false;
                    far_inode.i_addr[m] = 0;
                }
                else
                {
                    if (!bwrite(&far_d_last, far_inode.i_addr[m], DIR))
                        return false;
                }
            }
            break;
        }
    }
    if (!iwrite(&far_inode, far_i)) //写回父i节点
        return false;
    return true;
}

bool removeFile(char *filepath, unsigned type) //删除文件, type: 文件种类
{
    int rm_i, far_i;
    char temp_path[1024];
    inode rm_inode;
    strcpy(temp_path, filepath);
    if (temp_path[0] != '/')
        relative2absolute(temp_path, current_i);                        //获取绝对路径
    if ((rm_i = filePath2inode(temp_path, current_i, 3, NORMAL)) == -2) //权限不足
    {
        printf("rm: 权限不足: %s\n", filepath);
        return false;
    }
    else if (rm_i == -1)
    {
        printf("rm: 不是目录: %s\n", filepath);
        return false;
    }
    else if (rm_i == 0)
    {
        printf("rm: 文件或目录不存在: %s\n", filepath);
        return false;
    }
    else
    {
        // printf("开始在父目录中删除该文件 %d\n", rm_i);
        if ((far_i = getFartherInode(temp_path)) <= 0) //成功获取待删除节点父节点
        {
            printf("获取父亲i节点号失败\n");
            return false;
        }
        // printf("获取父亲i节点号成功 %d\n", far_i);
        if (!iread(&rm_inode, rm_i))
            return false;

        if (rm_inode.i_ilink == 1) //文件联接数为1, 删除文件i节点和数据块
        {
            if (rm_inode.i_type == DIR) //待删除文件为目录
            {
                if (type == DIR) //有命令行 -r 参数
                {
                    // printf("%d\n", rm_inode.i_ilink);
                    if (!removeDirFile(rm_i))
                    {
                        printf("rm: 删除\'%s\'失败\n", filepath);
                        return false;
                    }
                }
                else //无命令行 -r 参数
                {
                    printf("rm: 无法删除\'%s\': 是一个目录\n", filepath);
                    return false;
                }
            }
            else //待删除文件为普通文件
            {
                if (!removeDirFile(rm_i))
                    return false;
            }
        }
        else //文件联接数大于1, 文件联接数-1
        {
            rm_inode.i_ilink--;
        }
        if (!removeFileFromFar(far_i, rm_i))
        {
            printf("从父目录删除该目录失败\n");
            return false;
        }
        return true;
    }
}

bool _open(char *file_name) //打开文件
{
    char temp_path[1024];
    strcpy(temp_path, file_name);
    if (temp_path[0] != '/')
        relative2absolute(temp_path, current_i);                          //获取绝对路径
    if ((open_i = filePath2inode(temp_path, current_i, 3, NORMAL)) == -2) //权限不足
    {
        printf("open: 权限不足: %s\n", file_name);
        return false;
    }
    else if (open_i == -1)
    {
        printf("open: 不是目录: %s\n", file_name);
        return false;
    }
    else if (open_i == 0)
    {
        printf("open: 文件或目录不存在: %s\n", file_name);
        return false;
    }
    else
    {
        if (!iread(&open_ino, open_i))
            return false;
    }
    return true;
}

int _read(int loc, char *buf) //读取已经打开了的文件，每次读取一个数据块
{
    int addr_i = loc / BLOCK_SIZE;
    if (addr_i > open_ino.i_size / BLOCK_SIZE)
    {
        // printf("read: 起始地址越界\n");
        return true;
    }
    else if (addr_i < 9) //起始地址所在的数据块为直接索引数据块
    {
        if (!bread(buf, open_ino.i_addr[addr_i], NORMAL))
            return false;
    }
    else //起始地址所在的数据块为一级间接索引数据块
    {
        unsigned addr[BLOCK_SIZE / sizeof(unsigned)];
        if (!bread(addr, open_ino.i_addr[9], NORMAL))
            return false;
        if (!bread(buf, addr[addr_i - 9], NORMAL))
            return false;
    }
    return true;
}

bool appendChar(char *des, char *src, int d_begin, int s_begin, int len) //在char数组特定位置追加数据
{
    int i, j;
    for (i = d_begin, j = s_begin; j < len; i++, j++)
    {
        des[i] = src[j];
    }
    des[i] = '\0';
    return true;
}

int _write(char *buf, int length) //写入已经打开的文件， 支持最大写入量：一个数据块
{
    int addr_i = (open_ino.i_size + 2) / BLOCK_SIZE;
    int addr_i_end = (open_ino.i_size + length + 2) / BLOCK_SIZE;
    int last_size = open_ino.i_size % BLOCK_SIZE;
    char temp_buf[BLOCK_SIZE + 2];
    if (open_ino.i_size == 0) //打开的文件大小为0，即无数据块
    {
        int b_num = balloc(); //申请新的数据块
        if (b_num == 0)
            return false;
        memset(temp_buf, '\0', BLOCK_SIZE + 2);
        appendChar(temp_buf, buf, last_size, 0, length); //追加内容
        open_ino.i_size += length;                       //更新文件长度
        temp_buf[length + 1] = EOF;                      //文件结束标记
        if (!bwrite(temp_buf, b_num, NORMAL))            //写回更改后的数据块
            return false;
        open_ino.i_addr[0] = b_num; //数据块号加入i节点addr
    }
    else if (addr_i < 9) //最后一个数据块为直接索引
    {
        if (!bread(temp_buf, open_ino.i_addr[addr_i], NORMAL)) //读取最后一个数据块
            return false;
        if (addr_i == addr_i_end) //写入文件不需要增加数据块
        {
            appendChar(temp_buf, buf, last_size, 0, length);        //追加内容
            open_ino.i_size += length;                              //更新文件长度
            temp_buf[last_size + length + 1] = EOF;                 //文件结束标记
            if (!bwrite(temp_buf, open_ino.i_addr[addr_i], NORMAL)) //写回更改后的数据块
                return false;
        }
        else //写入文件需要增加数据块
        {
            appendChar(temp_buf, buf, last_size, 0, BLOCK_SIZE - last_size); //先向最后一个数据块追加内容
            if (!bwrite(temp_buf, open_ino.i_addr[addr_i], NORMAL))          //写回更改后的数据块
                return false;
            unsigned b_num, b_num1;
            if ((b_num = balloc()) == false) //申请新的数据块
                return false;

            appendChar(temp_buf, buf, 0, BLOCK_SIZE - last_size, length - (BLOCK_SIZE - last_size)); //向新申请的数据块写入数据
            temp_buf[length - (BLOCK_SIZE - last_size) + 1] = EOF;                                   //文件结束标记
            open_ino.i_size += length;                                                               //更新文件长度
            if (!bwrite(temp_buf, b_num, NORMAL))                                                    //写回更改后的数据块
                return false;
            if (addr_i == 8) //新创建的数据块为一级间接索引
            {
                if ((b_num1 = balloc()) == false) //申请一级间接索引节点数据块
                    return false;

                open_ino.i_addr[9] = b_num1;                            //保存一级间接索引节点数据块块号
                unsigned addr_array[BLOCK_SIZE / sizeof(unsigned)];     //一级间接索引节点缓冲区
                for (int i = 1; i < BLOCK_SIZE / sizeof(unsigned); i++) //初始化一级间接索引节点缓冲区
                    addr_array[i] = 0;
                addr_array[0] = b_num; //保存文件最后一个数据块
                if (!bwrite(addr_array, b_num1, NORMAL))
                    return false;
            }
            else
            {
                open_ino.i_addr[addr_i + 1] = b_num; //保存文件最后一个数据块
            }
        }
    }
    else //最后一个数据块为一级间接索引
    {
        unsigned addr_array[BLOCK_SIZE / sizeof(unsigned)]; //一级间接索引节点缓冲区
        if (!bread(addr_array, open_ino.i_addr[9], NORMAL)) //读取一级间接索引节点
            return false;
        if (!bread(temp_buf, addr_array[addr_i - 9], NORMAL)) //读取最后一个数据块
            return false;
        if (addr_i == addr_i_end) //写入文件不需要增加数据块
        {
            appendChar(temp_buf, buf, last_size, 0, length);       //追加内容
            open_ino.i_size += length;                             //更新文件长度
            temp_buf[last_size + length + 1] = EOF;                //文件结束标记
            if (!bwrite(temp_buf, addr_array[addr_i - 9], NORMAL)) //写回更改后的数据块
                return false;
        }
        else //写入文件需要增加数据块
        {
            appendChar(temp_buf, buf, last_size, 0, BLOCK_SIZE - last_size); //先向最后一个数据块追加内容
            if (!bwrite(temp_buf, addr_array[addr_i - 9], NORMAL))           //写回更改后的数据块
                return false;
            unsigned b_num;
            if ((b_num = balloc()) == false) //申请新的数据块
                return false;
            appendChar(temp_buf, buf, 0, BLOCK_SIZE - last_size, length - (BLOCK_SIZE - last_size)); //向新申请的数据块写入数据
            open_ino.i_size += length;                                                               //更新文件长度
            temp_buf[length - (BLOCK_SIZE - last_size) + 1] = EOF;                                   //文件结束标记
            if (!bwrite(temp_buf, b_num, NORMAL))                                                    //写回更改后的数据块
                return false;
            addr_array[addr_i - 8] = b_num; //保存文件最后一个数据块
            if (!bwrite(addr_array, open_ino.i_addr[9], NORMAL))
                return false;
        }
    }
    return true;
}

bool _close(unsigned close_i) //关闭已经打开的文件
{
    if (!iwrite(&open_ino, open_i))
    {
        printf("close: 文件不存在或未打开\n");
        return false;
    }
    else
    {
        open_i = 0;
        return true;
    }
}

bool workLoop() //工作循环
{
    char comm_buf[1024]; //命令缓冲区
    char command[128];   //命令
    int num;
    while (true)
    {
        printCommandTip(); //打印命令提示头
        gets(comm_buf);
        num = sscanf(comm_buf, " %s %[^\n]", command, comm_buf);
        if (strcmp(command, "touch") == 0) //touch 创建文件
        {
            if (num == 1)
            {
                printf("touch: 参数过少\n");
                continue;
            }
            while (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
            {
                if (!checkName(command, current_i))  //判断所touch的文件是否存在
                    refrushTime(command, current_i); //文件存在，更新时间戳
                else if (!createFile(command, NORMAL))
                    break;
            }
            if (!checkName(command, current_i))  //判断所touch的文件是否存在
                refrushTime(command, current_i); //文件存在，更新时间戳
            else if (!createFile(command, NORMAL))
                continue;
        }
        else if (strcmp(command, "mkdir") == 0) //mkdir 创建文件夹
        {
            if (num == 1)
            {
                printf("mkdir: 参数过少\n");
                continue;
            }
            while (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
            {
                if (!checkName(command, current_i)) //判断所mkdir的文件是否存在
                    printf("mkdir: 无法创建目录\"%s\": 文件已存在\n", command);
                else if (!createFile(command, DIR))
                    break;
            }
            if (!checkName(command, current_i)) //判断所mkdir的文件是否存在
                printf("mkdir: 无法创建目录\"%s\": 文件已存在\n", command);
            else if (!createFile(command, DIR))
                break;
        }
        else if (strcmp(command, "cd") == 0) //cd 切换工作目录
        {
            if (num == 1)
            {
                printf("cd: 参数过少\n");
                continue;
            }
            if (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
            {
                printf("cd: 参数过多\n");
                continue;
            }
            if (!changeDir(command, current_i))
                continue;
        }
        else if (strcmp(command, "ls") == 0) //ls 显示当前目录下文件
        {
            if (num == 1)
            {
                showDir("");
                continue;
            }
            if (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
            {
                printf("cd: 参数过多\n");
                continue;
            }
            if (!showDir(command))
                continue;
        }
        else if (strcmp(command, "pwd") == 0) //pwd 显示当前工作目录路径
        {
            if (strcmp(command, comm_buf) != 0)
            {
                printf("pwd: 参数过多\n");
                continue;
            }
            memset(comm_buf, '\0', 1024);
            if (!printWorkingDir(comm_buf, current_i))
                continue;
            printf("%s\n", comm_buf);
        }
        else if (strcmp(command, "rm") == 0) //rm 删除文件
        {
            if (num == 1)
            {
                printf("rm: 缺少操作数\n");
                continue;
            }
            sscanf(comm_buf, " %s", command);
            if (strcmp(command, "-r") == 0) //递归删除文件
            {
                sscanf(comm_buf, " %s %[^\n]", command, comm_buf);
                while (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
                {
                    if (!removeFile(command, DIR))
                        break;
                }
                if (!removeFile(command, DIR))
                    continue;
            }
            else //非递归删除文件
            {
                while (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
                {
                    if (!removeFile(command, DIR))
                        break;
                }
                if (!removeFile(command, NORMAL))
                    continue;
            }
        }
        else if (strcmp(command, "cat") == 0) //cat 查看当前目录下文件内容
        {
            if (num == 1)
            {
                printf("cat: 参数过少\n");
                continue;
            }
            if (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
            {
                printf("cat: 参数过多\n");
                continue;
            }
            if (!catFile(command))
                continue;
        }
        else if (strcmp(command, "vi") == 0) //vi 当前目录下文件
        {
            if (num == 1)
            {
                printf("vi: 参数过少\n");
                continue;
            }
            if (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
            {
                printf("vi: 参数过多\n");
                continue;
            }
            if (!vi_file(command))
                continue;
        }
        else if (strcmp(command, "chusr") == 0) //chUsr 更改登录用户
        {
            if (strcmp(command, comm_buf) != 0)
            {
                printf("chusr: 参数过多\n");
                continue;
            }
            if (!changeUsr())
                continue;
            setbuf(stdin, NULL);
        }
        else if (strcmp(command, "addusr") == 0) //addusr 增加用户
        {
            if (strcmp(command, comm_buf) != 0)
            {
                printf("addusr: 参数过多\n");
                continue;
            }
            if (!addUsr())
                continue;
            setbuf(stdin, NULL);
        }
        else if (strcmp(command, "rmusr") == 0) //rmusr 删除用户
        {
            if (num == 1)
            {
                printf("rmusr: 参数过少\n");
                continue;
            }
            while (sscanf(comm_buf, " %s %[^\n]", command, comm_buf) != 1)
            {
                if (!removeUsr(command))
                    continue;
            }
            if (!removeUsr(command))
                continue;
        }
        else if (strcmp(command, "lsusr") == 0) //lsusr 显示用户信息
        {
            if (strcmp(command, comm_buf) != 0)
            {
                printf("lsusr: 参数过多\n");
                continue;
            }
            if (!lsUsr())
                continue;
        }
        else if (strcmp(command, "format") == 0) //format 格式化文件系统
        {
            if (strcmp(command, comm_buf) != 0)
            {
                printf("pwd: 参数过多\n");
                continue;
            }
            fclose(fp);
            if (remove("system_disk") == -1)
            {
                printf("文件系统格式化失败！\n");
                break;
            }
            if (loadSystem() == false) //载入文件系统
            {
                printf("载入文件系统失败!\n");
                return -1;
            }
        }
        else if (strcmp(command, "help") == 0) //help 显示帮助信息
        {
            if (strcmp(command, comm_buf) != 0)
            {
                printf("pwd: 参数过多\n");
                continue;
            }
            printHelp();
        }
        else if (strcmp(command, "exit") == 0) //exit 退出文件系统
            break;
        else
        {
            printf("未找到命令: %s\n", command);
            continue;
        }
    }
    return true;
}

//打印显示帮助信息
void printHelp()
{
    printf("名称：pwd    格式：pwd              功能：显示当前目录路径\n");
    printf("名称：ls     格式：ls [option]      功能：显示当前目录文件信息\n");
    printf("                 -l  列表显示文件详细信息\n");
    printf("                 -a  显示所有文件及目录\n");
    printf("                 -p  分类显示文件及目录，目录高亮且加反斜线\n");
    printf("名称：cd     格式：cd [filePath]  功能：改变工作目录到指定目录\n");
    printf("                 [filePath]  目录路径，可为相对或绝对路径\n");
    printf("名称：touch  格式：touch [file...]  功能：在当前目录下创建文件\n");
    printf("                 [file...]  文件名\n");
    printf("名称：mkdir  格式：mkdir [file...]  功能：在当前目录下创建目录\n");
    printf("                 [file...]  目录名\n");
    printf("名称：rm     格式：rm [option] [file...]  功能：删除指定文件\n");
    printf("                 -r  递归删除文件\n");
    printf("                 [file...]  目录名\n");
    printf("名称：cat    格式：cat [file]   功能：查看指定文件内容\n");
    printf("                 [file]  文件名\n");
    printf("名称：vi     格式：vi [file]   功能：修改指定文件内容\n");
    printf("                 [file]  文件名\n");
    printf("                 ctrl+d 退出编辑\n");
    printf("名称：chusr  格式：chusr     功能：更换登录用户\n");
    printf("名称：rmusr  格式：rmusr     功能：删除用户\n");
    printf("名称：addusr 格式：addusr    功能：增加用户\n");
    printf("名称：lsusr  格式：lsusr     功能：显示所有用户信息\n");
    printf("名称：format 格式：format    功能：格式化文件系统\n");
    printf("名称：exit   格式：exit      功能：退出文件系统\n");
}

//更改登录用户
bool changeUsr()
{
    char name[32], password[32];
    printf("用户名：");
    scanf("%s", name);
    printf("密码：");
    scanf("%s", password);
    for (int i = 0; i < pd.all_usr; i++)
    {
        if (!strcmp(name, pd.entry[i].user_name))
        {
            if (!strcmp(password, pd.entry[i].password))
            {
                pd.current_usr = i;
                return true;
            }
            else
            {
                printf("密码错误！\n");
                return false;
            }
        }
    }
    printf("用户不存在！\n");
    return false;
}

//增加用户，仅root用户
bool addUsr()
{
    if (pd.current_usr != 0) //当前用户不是root
    {
        printf("非root用户，无法新增用户\n");
        return false;
    }
    char name[32], password[32];
    printf("新增用户名：");
    scanf("%s", name);
    printf("密码：");
    scanf("%s", password);
    //保存新增用户信息
    strcpy(pd.entry[pd.all_usr].user_name, name);
    strcpy(pd.entry[pd.all_usr].password, password);
    pd.entry[pd.all_usr].p_uid = pd.all_usr++;
    return true;
}

//删除用户，仅root用户
bool removeUsr(char *name)
{
    if (pd.current_usr != 0) //当前用户不是root
    {
        printf("非root用户，无法删除用户\n");
        return false;
    }
    if (!strcmp(name, "root"))
    {
        printf("无法删除root用户\n");
        return false;
    }
    for (int i = 1; i < pd.all_usr; i++) //查找符合的用户名
    {
        if (!strcmp(name, pd.entry[i].user_name))
        {
            for (int j = i; j < pd.all_usr - 1; j++)
                pd.entry[j] = pd.entry[j + 1];
            pd.all_usr--;
            return true;
        }
    }
    printf("无此用户名：%s\n", name);
    return false;
}

//显示所有用户信息，仅root用户
bool lsUsr()
{
    if (pd.current_usr != 0) //当前用户不是root
    {
        printf("非root用户，无法查看用户\n");
        return false;
    }
    printf("用户ID   用户名    密码\n");
    for (int i = 0; i < pd.all_usr; i++) //打印所有用户
        printf("  %-7d%-10s%s\n", pd.entry[i].p_uid, pd.entry[i].user_name, pd.entry[i].password);
    return true;
}

bool exitSystem() //退出系统
{
    if (bwrite(&su_b, 1, SUPBLK) == false)
        return false;
    if (bwrite(&pd, 3, PWD) == false)
        return false;
    fclose(fp);
    return true;
}

int main()
{
    if (loadSystem() == false) //载入文件系统
    {
        printf("载入文件系统失败!\n");
        return -1;
    }
    char temp[1024];
    strftime(temp, sizeof(temp), "%Y-%m-%d %H:%M:%S", localtime(&(ino.i_time)));
    printf("文件系统创建日期：%s\n\n", temp);

    printf("\033[1;34m帮助文档：\033[0m\n");
    printHelp();
    printf("\n");
    // printf("%d %d  %d %d\n", su_b.s_nfree, su_b.s_ninode, su_b.s_free[0], su_b.s_inode[0]);

    // _open("1");
    // catFile("1");
    // printf("%d\n", open_ino.i_size);

    // createFile("home", DIR);
    // showDir("-ap");

    // showDir("-lap");
    // pd.current_usr = 0;
    // printCommandTip();
    // if (!changeDir("/home", current_i))
    // {
    //     printf("cd: 没有那个文件或目录: home\n");
    // }
    // printCommandTip();
    // showDir("-lap");
    // changeDir("../proc", current_i);
    // // createFile("123", DIR);
    // showDir("-lap");
    // changeDir("./123", current_i);
    // // createFile("stat", NORMAL);
    // showDir("-lp");
    // memset(temp, '\0', 1024);
    // printWorkingDir(temp, current_i);
    // printf("%s\n", temp);
    workLoop();
    // printf("%d %d  %d %d\n", su_b.s_nfree, su_b.s_ninode, su_b.s_free[0], su_b.s_inode[0]);
    if (exitSystem() == false)
    {
        printf("退出文件系统失败!\n");
        return -1;
    }
    else
        printf("退出文件系统...\n さようなら\n");
    return 0;
}